#include <stdio.h>
// 操作符
int main()
{
    // /得到商，%得到余数
    double aaa = 5 / 2;
    printf("aaa === %lf\n", aaa);
    ///////////////////////////////////////////////////////////////////////////////////////////////////////
    // 右移位接操作符  >>  算数右移
    // 右边丢弃，左边补原符号位
    // 数字在内存中保存的是补码，按照补码右移。 >> 右移,相当于/2;
    int ccc = -1 >> 1;
    printf("ccc === %d\n", ccc);
    // 左移
    // 左边丢弃，右边补0。    << 左移,相当于*2;  
    int ddd = 1 << 1;
    printf("ddd === %d\n", ddd);
    int eee = -1 << 1;
    printf("eee === %d\n", eee);
    // ps:对于移位运算符，不要移动负数位，这个是标准未定义的。
    ///////////////////////////////////////////////////////////////////////////////////////////////////////
    // 位操作符（只对整数，补码：正数的原、反、补相同），
    // & - 按2进制位与 全1得1。
    // | - 按2进制位或 全0得0
    // ^ - 按2进制位异或， 同0，异1
    //   - 按2进制位同或， 同1，异0
    ///////////////////////////////////////////////////////////////////////////////////////////////////////
    // 交换两个数的值，不使第三个变量
    // 方法1 ，可能会溢出
    int fff = 3;
    int ggg = 4;
    fff = fff + ggg;
    ggg = fff - ggg;
    fff = fff - ggg;
    printf("fff === %d\n", fff);
    printf("ggg === %d\n", ggg);
    // 方法2，使用异或,效率不高，不易理解。
    int hhh = 3;
    int iii = 4;
    hhh = hhh ^ iii;
    iii = hhh ^ iii;
    hhh = hhh ^ iii;
    printf("hhh === %d\n", hhh);
    printf("iii === %d\n", iii);
    ///////////////////////////////////////////////////////////////////////////////////////////////////////
    // 统计一个正数存储在内存中的二进制中1的个数
    // 方法1、
    int num = 3;
    int count = 0;
    while (num)
    {
        if (num % 2 == 1)
        {
            count++;
        }
        num = num / 2;
    }
    printf("count = %d \n", count);
    // 方法2、
    int numEx = 3;
    int countEx = 0;
    for (int i = 0; i < 32; i++)
    {
        if (1 == ((numEx >> i) & 1))
        { // 这里要特别注意操作符的优先级
            countEx++;
        }
    }
    printf("countEx = %d \n", countEx);
    ///////////////////////////////////////////////////////////////////////////////////////////////////////
    // 赋值操作符
    // 复合赋值符
    numEx += 3;
    numEx -= 3;
    numEx *= 3;
    numEx /= 3;
    numEx %= 3;
    numEx >>= 3;
    numEx <<= 3;
    numEx &= 3;
    numEx |= 3;
    numEx ^= 3;
    ///////////////////////////////////////////////////////////////////////////////////////////////////////
    // 单目操作符,只有一个操作数。
    // ! + - &：取地址；
    // sizeof():类型长度；
    // ~ 按（2进制）位取反
    // ++  -- *间接访问操作符（解引用操作符）
    // (类型) 强制类型转换
    int c = 1;
    int d = ~c;              // d是有符号的整形
    printf("d === %d\n", d); // 输出 -2

    int a = 5 / 2;
    printf("a is %d \n", sizeof(a)); // 输出 4
    printf("a = %d \n", sizeof a);   // 计算变量的长度时，可以省略括号。输出 4
    // printf("%d \n",sizeof int); // 这里报错
    int arr[2] = {1, 2};
    printf("arr is %d \n", sizeof arr);                          // 输出8,2个int
    printf("arr length is %d \n", sizeof(arr) / sizeof(arr[1])); // 数组的长度 = 总长度/每个元素的长度

    ///////////////////////////////////////////////////////////////////////////////////////////////////////
    // sizeof
    short jjj = 0;
    int kkk = 10;
    printf("jjj sizeof === %d\n", sizeof(jjj = kkk + 5)); // 输出2，是short长度
    printf("jjj ==1== %d\n", jjj); // 输出 0。sizeof 不参与真实运算
    jjj = kkk + 5;
    printf("jjj ==2== %d\n", jjj);
    ///////////////////////////////////////////////////////////////////////////////////////////////////////
    // 关系操作符  >; >=; <; <=; !=; ==;
    ///////////////////////////////////////////////////////////////////////////////////////////////////////
    // 逻辑操作符  ||  &&
    int i = 0, lll = 1,mmm = 2,nnn = 3,ooo = 4;
    i = lll++ || ++mmm || ooo++; // 当lll++执行之后可计算出i为1，后面的++mmm,ooo++就不会再继续运算。
    printf("lll = %d,mmm = %d,nnn = %d,ooo = %d \n", lll, mmm, nnn, ooo); // 输出 lll = 2,mmm = 2,nnn = 3,ooo = 4
    ///////////////////////////////////////////////////////////////////////////////////////////////////////
    // 条件操作符(三目操作符)
    // exp1?exp2:exp3
    int ppp = 0;
    int qqq = ppp > 1 ? 10:20;
    printf("qqq ==2== %d\n", qqq); // 输出20
    
    return 0;
}